package edu.hdu.hangzhe.main;

import edu.hdu.hangzhe.bytecode.domain.*;
import edu.hdu.hangzhe.core.BytecodeParser;
import edu.hdu.hangzhe.utils.ABILUtils;

import java.util.ArrayList;
import java.util.Set;

public class ABILGenerator {

    /**
     * 生成ABIL
     * @param root target目录
     * @param className 类名称 package.className
     * @param methodName 方法名称
     * @param lineStart 对应源码起始行
     * @param lineEnd 对应源码结束行
     * @return ABIL
     */
    public static ArrayList<ABI> genABIL(String root, String className, String methodName, Integer lineStart, Integer lineEnd) {
        ByteCode byteCode = BytecodeParser.parse(root, className);
        Method method = byteCode.getMethod(methodName);
        return lineStart == null || lineEnd == null ? method.ABIL : method.filterABIL(lineStart, lineEnd);
    }

    /**
     * 生成ABIL Edits
     * @param root1 项目1 target目录
     * @param className1 类1名称 package.className1
     * @param methodName1 方法名称1
     * @param lineStart1 开始行
     * @param lineEnd1 结束行（包含）
     * @param root2 项目2 target目录
     * @param className2 类2名称 package.className1
     * @param methodName2 方法名称2
     * @param lineStart2 开始行
     * @param lineEnd2 结束行（包含）
     */
    public static ABILEdit genABILEdits(String root1, String className1, String methodName1, Integer lineStart1, Integer lineEnd1,
                                    String root2, String className2, String methodName2, Integer lineStart2, Integer lineEnd2) {
        ArrayList<ABI> ABIL1 = genABIL(root1, className1, methodName1, lineStart1, lineEnd1);
        ArrayList<ABI> ABIL2 = genABIL(root2, className2, methodName2, lineStart2, lineEnd2);
        Set<ArrayList<LCSUnit>> res = ABILUtils.getLCS(ABIL1, ABIL2);
        ArrayList<LCSUnit> list = (ArrayList<LCSUnit>) res.toArray()[0];
        ArrayList<OP> ops = new ArrayList<>();
        for (int k = 0; k < ABIL1.size(); ++k) {
            if (!ABILUtils.existABI(list, k, true)) {
                ops.add(new OP(OP.DEL, k, null));
            }
        }
        ArrayList<ABI> a = new ArrayList<>();
        int insertIndex = 0;
        for (int k = 0; k < ABIL2.size(); ++k) {
            if (!ABILUtils.existABI(list, k, false)) {
                a.add(ABIL2.get(k));
            } else {
                if (!a.isEmpty()) {
                    ops.add(new OP(OP.INS, insertIndex, new ArrayList<>(a)));
                    a.clear();
                }
                insertIndex = ABILUtils.A2B4LCSMap(list, k, false);
            }
        }
        if (!a.isEmpty()) {
            ops.add(new OP(OP.INS, insertIndex, a));
        }
        return new ABILEdit(ABIL1, ops);
    }

}
